home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 98 / Skunkware 98.iso / src / mail / pine3.96.tar.gz / pine3.96.tar / pine3.96 / imap / ANSI / c-client / tcp_dos.c < prev    next >
C/C++ Source or Header  |  1996-03-15  |  11KB  |  386 lines

  1. /*
  2.  * Program:    MS-DOS TCP/IP routines
  3.  *
  4.  * Author:    Mark Crispin
  5.  *        Networks and Distributed Computing
  6.  *        Computing & Communications
  7.  *        University of Washington
  8.  *        Administration Building, AG-44
  9.  *        Seattle, WA  98195
  10.  *        Internet: MRC@CAC.Washington.EDU
  11.  *
  12.  * Date:    11 April 1989
  13.  * Last Edited:    8 September 1995
  14.  *
  15.  * Copyright 1995 by the University of Washington
  16.  *
  17.  *  Permission to use, copy, modify, and distribute this software and its
  18.  * documentation for any purpose and without fee is hereby granted, provided
  19.  * that the above copyright notice appears in all copies and that both the
  20.  * above copyright notice and this permission notice appear in supporting
  21.  * documentation, and that the name of the University of Washington not be
  22.  * used in advertising or publicity pertaining to distribution of the software
  23.  * without specific, written prior permission.  This software is made
  24.  * available "as is", and
  25.  * THE UNIVERSITY OF WASHINGTON DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED,
  26.  * WITH REGARD TO THIS SOFTWARE, INCLUDING WITHOUT LIMITATION ALL IMPLIED
  27.  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, AND IN
  28.  * NO EVENT SHALL THE UNIVERSITY OF WASHINGTON BE LIABLE FOR ANY SPECIAL,
  29.  * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  30.  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, TORT
  31.  * (INCLUDING NEGLIGENCE) OR STRICT LIABILITY, ARISING OUT OF OR IN CONNECTION
  32.  * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  33.  *
  34.  */
  35.  
  36.                 /* TCP timeout handler routine */
  37. static tcptimeout_t tcptimeout = NIL;
  38.                 /* TCP timeouts, in seconds */
  39. static long tcptimeout_read = 0;
  40. static long tcptimeout_write = 0;
  41.  
  42. /* TCP/IP manipulate parameters
  43.  * Accepts: function code
  44.  *        function-dependent value
  45.  * Returns: function-dependent return value
  46.  */
  47.  
  48. void *tcp_parameters (long function,void *value)
  49. {
  50.   switch ((int) function) {
  51.   case SET_TIMEOUT:
  52.     tcptimeout = (tcptimeout_t) value;
  53.     break;
  54.   case GET_TIMEOUT:
  55.     value = (void *) tcptimeout;
  56.     break;
  57.   case SET_READTIMEOUT:
  58.     tcptimeout_read = (long) value;
  59.     break;
  60.   case GET_READTIMEOUT:
  61.     value = (void *) tcptimeout_read;
  62.     break;
  63.   case SET_WRITETIMEOUT:
  64.     tcptimeout_write = (long) value;
  65.     break;
  66.   case GET_WRITETIMEOUT:
  67.     value = (void *) tcptimeout_write;
  68.     break;
  69.   default:
  70.     value = NIL;        /* error case */
  71.     break;
  72.   }
  73.   return value;
  74. }
  75.  
  76. /* TCP/IP open
  77.  * Accepts: host name
  78.  *        contact service name
  79.  *        contact port number
  80.  * Returns: TCP/IP stream if success else NIL
  81.  */
  82.  
  83. TCPSTREAM *tcp_open (char *host,char *service,long port)
  84. {
  85.   TCPSTREAM *stream = NIL;
  86.   struct sockaddr_in sin;
  87.   int sock;
  88.   char *s,tmp[MAILTMPLEN];
  89.   if (s = strchr (host,':')) {    /* port number specified? */
  90.     *s++ = '\0';        /* yes, tie off port */
  91.     port = strtol (s,&s,10);    /* parse port */
  92.     if (s && *s) {
  93.       sprintf (tmp,"Junk after port number: %.80s",s);
  94.       mm_log (tmp,ERROR);
  95.       return NIL;
  96.     }
  97.   }
  98.   /* The domain literal form is used (rather than simply the dotted decimal
  99.      as with other Unix programs) because it has to be a valid "host name"
  100.      in mailsystem terminology. */
  101.   sin.sin_family = AF_INET;    /* family is always Internet */
  102.                 /* look like domain literal? */
  103.   if (host[0] == '[' && host[(strlen (host))-1] == ']') {
  104.     strcpy (tmp,host+1);    /* yes, copy number part */
  105.     tmp[strlen (tmp)-1] = '\0';
  106.     if ((sin.sin_addr.s_addr = inet_addr (tmp)) == -1) {
  107.       sprintf (tmp,"Bad format domain-literal: %.80s",host);
  108.       mm_log (tmp,ERROR);
  109.       return NIL;
  110.     }
  111.   }
  112.                 /* look up host name */
  113.   else if (!lookuphost (&host,&sin)) {
  114.     sprintf (tmp,"Host not found: %s",host);
  115.     mm_log (tmp,ERROR);
  116.     return NIL;
  117.   }
  118.  
  119.                 /* copy port number in network format */
  120.   if (!(sin.sin_port = htons (port))) fatal ("Bad port argument to tcp_open");
  121.                 /* get a TCP stream */
  122.   if ((sock = socket (sin.sin_family,SOCK_STREAM,0)) < 0) {
  123.     sprintf (tmp,"Unable to create TCP socket (%d)",errno);
  124.     mm_log (tmp,ERROR);
  125.     fs_give ((void **) &host);
  126.     return NIL;
  127.   }
  128.                 /* open connection */
  129.   if (connect (sock,(struct sockaddr *) &sin,sizeof (sin)) < 0) {
  130.     switch (errno) {        /* analyze error */
  131.     case ECONNREFUSED:
  132.       s = "Refused";
  133.       break;
  134.     case ENOBUFS:
  135.       s = "Insufficient system resources";
  136.       break;
  137.     case ETIMEDOUT:
  138.       s = "Timed out";
  139.       break;
  140.     default:
  141.       s = "Unknown error";
  142.       break;
  143.     }
  144.     sprintf (tmp,"Can't connect to %.80s,%ld: %s (%d)",host,port,s,errno);
  145.     mm_log (tmp,ERROR);
  146.     close (sock);
  147.     fs_give ((void **) &host);
  148.     return NIL;
  149.   }
  150.                 /* create TCP/IP stream */
  151.   stream = (TCPSTREAM *) fs_get (sizeof (TCPSTREAM));
  152.   stream->host = host;        /* official host name */
  153.   stream->localhost = cpystr (mylocalhost ());
  154.   stream->port = port;        /* port number */
  155.   stream->tcps = sock;        /* init socket */
  156.   stream->ictr = 0;        /* init input counter */
  157.   return stream;        /* return success */
  158. }
  159.   
  160. /* TCP/IP authenticated open
  161.  * Accepts: host name
  162.  *        service name
  163.  *        returned user name
  164.  * Returns: TCP/IP stream if success else NIL
  165.  */
  166.  
  167. TCPSTREAM *tcp_aopen (char *host,char *service,char *usrnam)
  168. {
  169.   return NIL;            /* always NIL on DOS */
  170. }
  171.  
  172. /* TCP/IP receive line
  173.  * Accepts: TCP/IP stream
  174.  * Returns: text line string or NIL if failure
  175.  */
  176.  
  177. char *tcp_getline (TCPSTREAM *stream)
  178. {
  179.   int n,m;
  180.   char *st,*ret,*stp;
  181.   char c = '\0';
  182.   char d;
  183.                 /* make sure have data */
  184.   if (!tcp_getdata (stream)) return NIL;
  185.   st = stream->iptr;        /* save start of string */
  186.   n = 0;            /* init string count */
  187.   while (stream->ictr--) {    /* look for end of line */
  188.     d = *stream->iptr++;    /* slurp another character */
  189.     if ((c == '\015') && (d == '\012')) {
  190.       ret = (char *) fs_get (n--);
  191.       memcpy (ret,st,n);    /* copy into a free storage string */
  192.       ret[n] = '\0';        /* tie off string with null */
  193.       return ret;
  194.     }
  195.     n++;            /* count another character searched */
  196.     c = d;            /* remember previous character */
  197.   }
  198.                 /* copy partial string from buffer */
  199.   memcpy ((ret = stp = (char *) fs_get (n)),st,n);
  200.                 /* get more data from the net */
  201.   if (!tcp_getdata (stream)) return NIL;
  202.                 /* special case of newline broken by buffer */
  203.   if ((c == '\015') && (*stream->iptr == '\012')) {
  204.     stream->iptr++;        /* eat the line feed */
  205.     stream->ictr--;
  206.     ret[n - 1] = '\0';        /* tie off string with null */
  207.   }
  208.                 /* else recurse to get remainder */
  209.   else if (st = tcp_getline (stream)) {
  210.     ret = (char *) fs_get (n + 1 + (m = strlen (st)));
  211.     memcpy (ret,stp,n);        /* copy first part */
  212.     memcpy (ret + n,st,m);    /* and second part */
  213.     fs_give ((void **) &stp);    /* flush first part */
  214.     fs_give ((void **) &st);    /* flush second part */
  215.     ret[n + m] = '\0';        /* tie off string with null */
  216.   }
  217.   return ret;
  218. }
  219.  
  220. /* TCP/IP receive buffer
  221.  * Accepts: TCP/IP stream
  222.  *        size in bytes
  223.  *        buffer to read into
  224.  * Returns: T if success, NIL otherwise
  225.  */
  226.  
  227. long tcp_getbuffer (TCPSTREAM *stream,unsigned long size,char *buffer)
  228. {
  229.   unsigned long n;
  230.   char *bufptr = buffer;
  231.   while (size > 0) {        /* until request satisfied */
  232.     if (!tcp_getdata (stream)) return NIL;
  233.     n = min (size,stream->ictr);/* number of bytes to transfer */
  234.                 /* do the copy */
  235.     memcpy (bufptr,stream->iptr,n);
  236.     bufptr += n;        /* update pointer */
  237.     stream->iptr +=n;
  238.     size -= n;            /* update # of bytes to do */
  239.     stream->ictr -=n;
  240.   }
  241.   bufptr[0] = '\0';        /* tie off string */
  242.   return T;
  243. }
  244.  
  245.  
  246. /* TCP/IP receive data
  247.  * Accepts: TCP/IP stream
  248.  * Returns: T if success, NIL otherwise
  249.  */
  250.  
  251. long tcp_getdata (TCPSTREAM *stream)
  252. {
  253.   int i;
  254.   fd_set fds,efds;
  255.   struct timeval tmo;
  256.   time_t t = time (0);
  257.   tmo.tv_sec = tcptimeout_read;
  258.   tmo.tv_usec = 0;
  259.   FD_ZERO (&fds);        /* initialize selection vector */
  260.   FD_ZERO (&efds);        /* handle errors too */
  261.   if (stream->tcps < 0) return NIL;
  262.   while (stream->ictr < 1) {    /* if nothing in the buffer */
  263.     FD_SET (stream->tcps,&fds);    /* set bit in selection vector */
  264.     FD_SET (stream->tcps,&efds);/* set bit in selection vector */
  265.     errno = NIL;        /* block and read */
  266.     while (((i = select (stream->tcps+1,&fds,0,&efds,
  267.              tmo.tv_sec ? &tmo : (struct timeval *) 0)) < 0) &&
  268.        (errno == EINTR));
  269.     if (!i) {            /* timeout? */
  270.       if (tcptimeout && ((*tcptimeout) (time (0) - t))) continue;
  271.       else return tcp_abort (stream);
  272.     }
  273.     if (i < 0) return tcp_abort (stream);
  274.     while (((i = read (stream->tcps,stream->ibuf,BUFLEN)) < 0) &&
  275.        (errno == EINTR));
  276.     if (i < 1) return tcp_abort (stream);
  277.     stream->iptr = stream->ibuf;
  278.     stream->ictr = i;        /* set new byte pointer and count */
  279.   }
  280.   return T;
  281. }
  282.  
  283. /* TCP/IP send string as record
  284.  * Accepts: TCP/IP stream
  285.  *        string pointer
  286.  * Returns: T if success else NIL
  287.  */
  288.  
  289. long tcp_soutr (TCPSTREAM *stream,char *string)
  290. {
  291.   return tcp_sout (stream,string,(unsigned long) strlen (string));
  292. }
  293.  
  294.  
  295. /* TCP/IP send string
  296.  * Accepts: TCP/IP stream
  297.  *        string pointer
  298.  *        byte count
  299.  * Returns: T if success else NIL
  300.  */
  301.  
  302. long tcp_sout (TCPSTREAM *stream,char *string,unsigned long size)
  303. {
  304.   long i;
  305.   struct timeval tmo;
  306.   fd_set fds;
  307.   time_t t = time (0);
  308.   tmo.tv_sec = tcptimeout_write;
  309.   tmo.tv_usec = 0;
  310.   FD_ZERO (&fds);        /* initialize selection vector */
  311.   if (stream->tcps < 0) return NIL;
  312.   while (size > 0) {        /* until request satisfied */
  313.     FD_SET (stream->tcps,&fds);    /* set bit in selection vector */
  314.                 /* block and write */
  315.     if (((i = select (stream->tcps+1,0,&fds,0,
  316.               tmo.tv_sec ? &tmo : (struct timeval *) 0)) > 0) &&
  317.     ((i = write (stream->tcps,string,size)) >= 0)) {
  318.       size -= i;        /* count this size */
  319.       string += i;
  320.     }
  321.                 /* error or timeout */
  322.     else if (i || !(tcptimeout && ((*tcptimeout) (time (0) - t))))
  323.       return tcp_abort (stream);
  324.   }
  325.   return T;            /* all done */
  326. }
  327.  
  328. /* TCP/IP close
  329.  * Accepts: TCP/IP stream
  330.  */
  331.  
  332. void tcp_close (TCPSTREAM *stream)
  333. {
  334.   tcp_abort (stream);        /* nuke the socket */
  335.                 /* flush host names */
  336.   fs_give ((void **) &stream->host);
  337.   fs_give ((void **) &stream->localhost);
  338.   fs_give ((void **) &stream);    /* flush the stream */
  339. }
  340.  
  341.  
  342. /* TCP/IP abort stream
  343.  * Accepts: TCP/IP stream
  344.  * Returns: NIL always
  345.  */
  346.  
  347. long tcp_abort (TCPSTREAM *stream)
  348. {
  349.   if (stream->tcps >= 0) close (stream->tcps);
  350.   stream->tcps = -1;
  351.   return NIL;
  352. }
  353.  
  354.  
  355. /* TCP/IP get host name
  356.  * Accepts: TCP/IP stream
  357.  * Returns: host name for this stream
  358.  */
  359.  
  360. char *tcp_host (TCPSTREAM *stream)
  361. {
  362.   return stream->host;        /* return host name */
  363. }
  364.  
  365.  
  366. /* TCP/IP return port for this stream
  367.  * Accepts: TCP/IP stream
  368.  * Returns: port number for this stream
  369.  */
  370.  
  371. long tcp_port (TCPSTREAM *stream)
  372. {
  373.   return stream->port;        /* return port number */
  374. }
  375.  
  376.  
  377. /* TCP/IP get local host name
  378.  * Accepts: TCP/IP stream
  379.  * Returns: local host name
  380.  */
  381.  
  382. char *tcp_localhost (TCPSTREAM *stream)
  383. {
  384.   return stream->localhost;    /* return local host name */
  385. }
  386.